package com.hkd.config;

import com.alibaba.fastjson.JSONObject;
import com.hkd.common.api.constants.AuthConstants;
import com.hkd.common.api.constants.CacheConstants;
import com.hkd.user_service.api.SysUserService;
import com.hkd.user_service.api.entity.SysUser;
import com.hkd.user_service.api.vo.BaseUserInfo;
import com.hkd.utils.MyJwtAccessTokenConverter;
import com.hkd.utils.RSAUtil;
import com.hkd.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.sql.DataSource;
import java.util.Map;

/**
 * 授权服务器配置
 * @author HKD
 * @date 2022/8/21 21:42
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //认证管理器
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysUserService sysUserService;

    @Bean
    protected JwtAccessTokenConverter jwtAccessTokenConverter(){
        MyJwtAccessTokenConverter myJwtAccessTokenConverter = new MyJwtAccessTokenConverter();
        myJwtAccessTokenConverter.setKeyPair(RSAUtil.GetKeyPair());
        return myJwtAccessTokenConverter;
    }
    @Bean
    public TokenStore jwtTokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter()){
            /**
             * 设置token并添加到redis
             * @param token
             * @param authentication
             */
            @Override
            public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) {
                Map<String, Object> map = token.getAdditionalInformation();
//                String jti = map.get(AuthConstants.JWT_TOKEN_KEY).toString();
                String userId = map.get(AuthConstants.JWT_USER_Id).toString();
                String account = map.get(AuthConstants.JWT_ACCOUNT).toString();
                String key= CacheConstants.USER_TOKE+userId;
                BaseUserInfo userInfo = sysUserService.getUserByAccount(account).getData();
                redisUtil.set(key, JSONObject.toJSONString(userInfo));
            }
        };
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConverter())
                .authenticationManager(this.authenticationManager);
    }

    /**
     * 授权端点开放
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                //开启/oauth/token_key验证端口无权限访问
                .tokenKeyAccess("permitAll()")
                //开启/oauth/check_token验证端口认证权限访问
                .checkTokenAccess("isAuthenticated()")
                //主要是让/oauth/token支持client_id以及client_secret作登录认证
                .allowFormAuthenticationForClients();
    }

    /**
     * 配置客户端详情信息
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
    }
}
